home *** CD-ROM | disk | FTP | other *** search
/ CD Exchange / CD Exchange - Volume 1.iso / utils / benchmark / aibb6.1 / documentation / bmark_code_information < prev    next >
Encoding:
Text File  |  1992-11-22  |  37.2 KB  |  1,473 lines

  1.  
  2.                                 A.I.B.B.
  3.                      Amiga Intuition Based Benchmarks
  4.            A system performance evaluation utility for the Amiga
  5.  
  6.                         Program Release Version 5.5
  7.                      Copyright 1991,1992 LaMonte Koop
  8.  
  9.                      Benchmark code examples and notes
  10.  
  11.     The code used for AIBB's benchmarking suite is rather simple in nature,
  12. but in order to provide a better view of what exactly each test does, a more
  13. thorough explanation for each is given in this document.  In addition, a
  14. 'pseudo-C' code representation of each test is also supplied.  This
  15. representation is not the full function itself, but rather a view of it
  16. which highlights the actual test material.  What is missing from these
  17. representations is mostly initialization and cleanup code, and in some places
  18. the full C syntax is not applied as used in AIBB itself.  However, this should
  19. give a fairly good picture of what is being done by AIBB during test
  20. performance.
  21.     It should be noted that the code used is by no means optimized in some
  22. areas.  Where optimization was prudent, it was used, but in some places this
  23. defeats the purpose.
  24.  
  25. ==============================================================================
  26.  
  27.                                 WritePixel
  28.  
  29.     The WritePixel test is a very simple display of a given system's graphics
  30. throughput.  It mainly deals with the operating system calls SetAPen()
  31. ( set the primary pen color ), and WritePixel() ( set a pixel in the current
  32. pen color ).  This is a basic test of the efficiency of the operating system
  33. functions, as well as the speed of the custom hardware on the Amiga in these
  34. simple matters.  Systems where the operating system kernel resides in a fast
  35. memory medium, as well as those which have more efficiency access to CHIP RAM
  36. resources will have the advantage with this test.  The code representation
  37. for this test is given below:
  38.  
  39.  
  40. WritePixel_Test()
  41. {
  42.     struct Screen *WPScreen;
  43.     struct RastPort *rp;
  44.     UWORD x;
  45.     UWORD y;
  46.     ULONG nulltime;
  47.  
  48.     /*
  49.      * Although not shown, the screen and rastport variables are first set
  50.      * up, then the test procedes at the following point....
  51.      */
  52.  
  53.     START_TEST_TIMER;
  54.  
  55.     SetAPen(rp,1);
  56.     for(y = 0; y < 200; y++)
  57.     {
  58.        for(x = 0; x < 320; x++)
  59.        {
  60.           WritePixel(rp,x,y);
  61.        }
  62.     }
  63.     SetAPen(rp,0);
  64.     for(x = 0; x < 320; x++)
  65.     {
  66.        for(y = 0; y < 200; y++)
  67.        {
  68.           WritePixel(rp,x,y);
  69.        }
  70.     }
  71.     SetAPen(rp,1);
  72.     for(y = 0; y < 200; y++)
  73.     {
  74.        Move(rp,0,y);
  75.        Draw(rp,319,y);
  76.     }
  77.     SetAPen(rp,0);
  78.     for(y = 0; y < 200; y++)
  79.     {
  80.        Move(rp,0,y);
  81.        Draw(rp,320,y);
  82.     }
  83.     SetAPen(rp,1);
  84.     for(y = 0; y < 200; y++)
  85.     {
  86.        Move(rp,0,y);
  87.        Draw(rp,319,y);
  88.     }
  89.     SetAPen(rp,0);
  90.     for(y = 0; y < 200; y++)
  91.     {
  92.        Move(rp,0,y);
  93.        Draw(rp,320,y);
  94.     }
  95.     SetAPen(rp,1);
  96.     for(y = 0; y < 200; y++)
  97.     {
  98.        Move(rp,0,y);
  99.        Draw(rp,319,y);
  100.     }
  101.     SetAPen(rp,0);
  102.     for(y = 0; y < 200; y++)
  103.     {
  104.        Move(rp,0,y);
  105.        Draw(rp,320,y);
  106.     }
  107.     SetAPen(rp,1);
  108.     for(y = 0; y < 200; y++)
  109.     {
  110.        for(x = 0; x < 320; x++)
  111.        {
  112.           WritePixel(rp,x,y);
  113.        }
  114.     }
  115.     SetAPen(rp,0);
  116.     for(x = 0; x < 320; x++)
  117.     {
  118.        for(y = 0; y < 200; y++)
  119.        {
  120.           WritePixel(rp,x,y);
  121.        }
  122.     }
  123.     STOP_TEST_TIMER;
  124.  
  125.     /* That concludes the actual test code portion of this function */
  126.     .................................................................
  127. }
  128.  
  129. ==============================================================================
  130.  
  131.                                   IMath
  132.  
  133.     IMath is a test of the primary integer/logical operational efficiency of
  134. a system.  Various integer arithmetic and logical function are performed in
  135. succession, and the calculations timed within a loop.  The loop variable
  136. itself is used within the calculations in order to provide a dynamic quality
  137. to the generated code, instead of static values being used at all times.
  138. This test performs its operations on longword ( 32-bit ) values exclusively.
  139.  
  140.  
  141. IMath_Test()
  142. {
  143.     LONG i;
  144.     LONG a = 2;
  145.     LONG b = 45;
  146.     LONG c = 22;
  147.  
  148.     START_TEST_TIMER;
  149.  
  150.     for(i=0; i < 100000 ; i++)
  151.     {
  152.        a = (a * b) + i;
  153.        b = (a * b) + (2 * i);
  154.        c += ((c * a) + b) + i;
  155.        c -= (((i + 1) - (a * b)) & ((b / a) | (i % 10))) + i;
  156.        c += ((b * c) - (b / a) - i) ^ i + c;
  157.        c -= (b / a) * (i + b);
  158.        c += (((b / a) * c) - i) ^ i + c;
  159.        c -= (((i + 1) - (a * b)) & ((b / a) | (i % 5))) - (5 * i);
  160.        c += (b / a) * i;
  161.        c -= (((b / a) * c) - i) ^ i + c;
  162.        c += (((i + 1)-(a * b)) & ((b / a) | (i % 7))) - i;
  163.        c -= (b / a) * (i - b);
  164.        b = (a * b) - (b ^ a) - i;
  165.        a = (a * b) + i;
  166.        c += ((b / a) - i) ^ i;
  167.     }
  168.  
  169.     STOP_TEST_TIMER;
  170.  
  171.     /*
  172.      *  At this point a global 'dummy' variable is used to assure that
  173.      *  code above is not optimized out.  This makes a global optimizer
  174.      *  believe the above results are needed in order to assign the
  175.      *  dummy variable a value
  176.      */
  177.  
  178.     TestDummy = a+b+c;
  179.  
  180.     /* The actual test code has concluded at this point */
  181.     .................................................................
  182. }
  183.  
  184. ==============================================================================
  185.  
  186.                                   Matrix
  187.  
  188.     This is AIBB's integer longword matrix manipulation test.  Three matrices
  189. are used in a variety of operations, with stress being placed upon matrix
  190. manipulation ( data movement ) functions, as these are often primary functions
  191. performed on matrices.  As the data here can not be kept entirely in registers
  192. for arithmetic manipulation, this test gives an indication of system
  193. performance when many data accesses are required outside of register values.
  194. The functions are also set up as to stress the calculation of data locations
  195. in the test timing.  Note that systems with larger caches ( such as the
  196. MC68040 ) will have a general advantage here, although the matrices are quite
  197. large enough as to not permit them to be entirely cached. The outline function
  198. for the matrix test and its associated functions is given below:
  199.  
  200.  
  201. void Matrix_Test()
  202. {
  203.      LONG *MatrixA;
  204.      LONG *MatrixB;
  205.      LONG *MatrixC;
  206.      UWORD i;
  207.      UWORD j;
  208.      UWORD k;
  209.  
  210.     /*
  211.      * Not shown, but the above LONG pointers are first initialized by
  212.      * allocating 10000 bytes of memory for each and assigning them
  213.      * to point at the base of each 'array'.
  214.      */
  215.  
  216.     /*
  217.      * The A and B arrays are first filled with values for later use
  218.      */
  219.  
  220.     for(i=0; i<50; i++)
  221.     {
  222.        for(j=0; j<50; j++)
  223.        {
  224.            MatrixA[50*i+j] = (LONG)i+(LONG)j;
  225.            MatrixB[50*i+j] = (LONG)(i+j) * (LONG)(j-i);
  226.        }
  227.     }
  228.  
  229.     START_TEST_TIMER;
  230.  
  231.     /*
  232.      * Here is the actual test code.  More emphasis is placed upon
  233.      * matrix data movement than arithmetic operation as many matrix-
  234.      * manipulation applications involve movement more than arithmetic
  235.      * (though, execeptions seem to be the rule here :) ).
  236.      * Though a purpose doesn't seem to be in mind here, it can give a
  237.      * general manipulation 'feel' for the system.
  238.      */
  239.  
  240.     for(k=0; k < 50; k++)
  241.     {
  242.        matrix_mult(MatrixA,MatrixB,MatrixC,50,50);
  243.        for(i=0; i<50; i++)
  244.        {
  245.           matrix_row_swap(MatrixC,i,49-i,50);
  246.           matrix_col_swap(MatrixC,49-i,i,50);
  247.        }
  248.        matrix_add(MatrixC,MatrixA,MatrixB,50,50);
  249.        matrix_sub(MatrixB,MatrixA,MatrixC,50,50);
  250.        matrix_transpose(MatrixC,MatrixA,50,50);
  251.     }
  252.  
  253.     STOP_TEST_TIMER;
  254.  
  255.     /*
  256.      * That concludes the test code proper.  Clean up operations are
  257.      * inserted following, and are not shown
  258.      */
  259.      ................................................................
  260. }
  261.  
  262. /*
  263.  * This function swaps rows in a matrix.
  264.  */
  265.  
  266. void matrix_row_swap(LONG *mat, UWORD ra, UWORD rb, UWORD ncols)
  267. {
  268.     UWORD c;
  269.     LONG t;
  270.  
  271.     for(c=0; c < ncols; c++)
  272.     {
  273.        t = mat[ra*ncols+c];
  274.        mat[ra*ncols+c] = mat[rb*ncols+c];
  275.        mat[rb*ncols+c] = t;
  276.     }
  277. }
  278.  
  279. /*
  280.  * Same as above, but for column-swapping.
  281.  */
  282.  
  283. void matrix_col_swap(LONG *mat, UWORD ca, UWORD cb, UWORD nrows)
  284. {
  285.     UWORD r;
  286.     LONG t;
  287.  
  288.     for(r=0; r < nrows; r++)
  289.     {
  290.        t = mat[r*nrows+ca];
  291.        mat[r*nrows+ca] = mat[r*nrows+cb];
  292.        mat[r*nrows+cb] = t;
  293.     }
  294. }
  295.  
  296. /*
  297.  * Add the contents of two matrices, and store the result in a third.
  298.  * Equivalent to [C] = [A] + [B]
  299.  */
  300.  
  301. void matrix_add(LONG *matA, LONG *matB, LONG *matC, UWORD rows, UWORD cols)
  302. {
  303.     UWORD r;
  304.     UWORD c;
  305.  
  306.     for(r=0; r < rows; r++)
  307.     {
  308.        for(c=0; c < cols; c++)
  309.        {
  310.           matC[r*cols+c] = matA[r*cols+c] + matB[r*cols+c];
  311.        }
  312.     }
  313. }
  314.  
  315. /*
  316.  * Subtract the contents of two matrices, and store the result in a third.
  317.  * Equivalent to [C] = [A] - [B].
  318.  */
  319.  
  320. void matrix_sub(LONG *matA, LONG *matB, LONG *matC, UWORD rows, UWORD cols)
  321. {
  322.     UWORD r;
  323.     UWORD c;
  324.  
  325.     for(r=0; r < rows; r++)
  326.     {
  327.        for(c=0; c<cols; c++)
  328.        {
  329.           matC[r*cols+c] = matA[r*cols+c] - matB[r*cols+c];
  330.        }
  331.     }
  332. }
  333.  
  334. /*
  335.  * Subtract the contents of two matrices, and store the result in a third.
  336.  * Equivalent to [C] = [A] * [B].
  337.  */
  338.  
  339. void matrix_mult(LONG *matA, LONG *matB, LONG *matC, UWORD rows, UWORD cols)
  340. {
  341.     UWORD r;
  342.     UWORD c;
  343.  
  344.     for(r=0; r<rows; r++)
  345.     {
  346.        for(c=0; c<cols; c++)
  347.        {
  348.           matC[r*cols+c] = matA[r*cols+c] * matB[r*cols+c];
  349.        }
  350.     }
  351. }
  352.  
  353. /*
  354.  * Transpose the contents of matrix [B] to matrix [A]
  355.  */
  356.  
  357. void matrix_transpose(LONG *matA, LONG *matB, UWORD rows, UWORD cols)
  358. {
  359.     UWORD r;
  360.     UWORD c;
  361.     LONG t;
  362.  
  363.     for(r=0; r < rows; r++)
  364.     {
  365.        for(c=0; c < cols; c++)
  366.        {
  367.           t = matA[r*cols+c];
  368.           matA[r*cols+c] = matB[r*cols+c];
  369.           matB[r*cols+c] = t;
  370.        }
  371.     }
  372. }
  373.  
  374. ==============================================================================
  375.  
  376.                                   MemTest
  377.  
  378.     This function was primarily designed to test only the data movement
  379. efficiency of the system across FAST RAM buses.
  380.  
  381. void MemTest()
  382. {
  383.     UBYTE *FMemArray1;
  384.     UBYTE *FMemArray2;
  385.  
  386.     /*
  387.      * First (not shown), two arrays of 32K in size are allocated and
  388.      * the reserved space split among the pointers above...
  389.      */
  390.  
  391.      .................................................................
  392.  
  393.     /*
  394.      * The actual test is a series of function calls, testing longword,
  395.      * word, and byte transfer times.
  396.      */
  397.  
  398.     START_TEST_TIMER;
  399.  
  400.     LongWordMemTest((ULONG *)FMemArray1,(ULONG *)FMemArray2,65);
  401.     WordMemTest((UWORD *)FMemArray1,(UWORD *)FMemArray2,65);
  402.     ByteMemTest((UBYTE *)FMemArray1,(UBYTE *)FMemArray2,65);
  403.     LongWordMemTest((ULONG *)FMemArray1,(ULONG *)FMemArray2,65);
  404.     WordMemTest((UWORD *)FMemArray1,(UWORD *)FMemArray2,65);
  405.     ByteMemTest((UBYTE *)FMemArray1,(UBYTE *)FMemArray2,65);
  406.  
  407.     STOP_TEST_TIMER;
  408.  
  409.     /*
  410.      * Clean up code would be placed in this location.
  411.      */
  412.      ...........................................................
  413. }
  414.  
  415. /*
  416.  * This function is responsible for LONGWORD memory access testing.
  417.  */
  418.  
  419. void LongWordMemTest(ULONG *MemArray1, ULONG *MemArray2, UWORD loops)
  420. {
  421.     UWORD i;
  422.     UWORD j;
  423.  
  424.     for(j=0; j < loops; j++)
  425.     {
  426.        for(i=0; i < 4096; i++)
  427.        {
  428.            *MemArray1++ = *MemArray2++;
  429.        }
  430.        for(i=0; i < 4096; i++)
  431.        {
  432.            *(--MemArray2) = *(--MemArray1);
  433.        }
  434.     }
  435. }
  436.  
  437. /*
  438.  * This function is responsible for WORD memory access testing.
  439.  */
  440.  
  441. void WordMemTest(UWORD *MemArray1, UWORD *MemArray2, UWORD loops)
  442. {
  443.     register UWORD i;
  444.     register UWORD j;
  445.  
  446.     for(j=0; j < loops; j++)
  447.     {
  448.        for(i=0; i < 8192; i++)
  449.        {
  450.            *MemArray1++ = *MemArray2++;
  451.        }
  452.        for(i=0; i < 8192; i++)
  453.        {
  454.            *(--MemArray2) = *(--MemArray1);
  455.        }
  456.     }
  457. }
  458.  
  459. /*
  460.  * This function is responsible for BYTE memory access testing.
  461.  */
  462.  
  463. void ByteMemTest(UBYTE *MemArray1, UBYTE *MemArray2, UWORD loops)
  464. {
  465.     UWORD i;
  466.     UWORD j;
  467.  
  468.     for(j=0; j < loops; j++)
  469.     {
  470.        for(i=0; i < 16384; i++)
  471.        {
  472.            *MemArray1++ = *MemArray2++;
  473.        }
  474.        for(i=0; i < 16384; i++)
  475.        {
  476.            *(--MemArray2) = *(--MemArray1);
  477.        }
  478.     }
  479. }
  480.  
  481. ==============================================================================
  482.  
  483.                                    Sieve
  484.  
  485.     This test is the basic Sieve of Erosthenes, used often to benchmark system
  486. performance at a basic level.  As the name implies, it is a 'sieve' for
  487. prime numbers, continuing up to the number 8191.  The test is a counting
  488. test, primarily involved in array initialization, and value assignment.
  489.  
  490.  
  491. void Sieve()
  492. {
  493.     UWORD k;
  494.     UWORD iter;
  495.     UWORD i;
  496.     UWORD count;
  497.     UWORD prime;
  498.     BOOL flags[8191];
  499.  
  500.     START_TEST_TIMER;
  501.  
  502.     for(iter=0; iter < 200; iter++)
  503.     {
  504.        count = 0;
  505.        for(i=0; i < 8191; i++) flags[i] = TRUE;
  506.        for(i=0; i < 8191; i++)
  507.        {
  508.           if(flags[i])
  509.           {
  510.              prime = i + i + 3;
  511.              for(k=i+prime; k < 8191; k += prime) flags[k] = FALSE;
  512.              count++;
  513.           }
  514.        }
  515.     }
  516.  
  517.     STOP_TEST_TIMER;
  518.  
  519.     /* End of test code */
  520.  
  521.     ..................................................................
  522. }
  523.  
  524. ==============================================================================
  525.  
  526.                                     Sort
  527.  
  528.     A simple sorting test on a 60000 byte array ( arranged as 16-bit WORD
  529. values ).  The algorithm used here is a shell-sort setup, with the array
  530. initialization itself also being part of the timed code.  The sorting is
  531. timed for 5 passes, to allow better resolution in the results. ( lower
  532. numbers of passes tend to be too fast on accelerated systems ).
  533.  
  534. void Sort()
  535. {
  536.     WORD *sarray;
  537.     WORD gap;
  538.     WORD temp;
  539.     WORD i;
  540.     WORD j;
  541.     BOOL nex;
  542.  
  543.     /*
  544.      * In initializing for this test, a 60000 byte array is allocated
  545.      * before the actual test code begins.
  546.      */
  547.  
  548.     ................................................................
  549.  
  550.     START_TEST_TIMER;
  551.  
  552.     for(j=0; j < 5; j++)
  553.     {
  554.  
  555.       /*
  556.         * The array is initialized first.  A non-random spreading setup
  557.         * is used to insure the same values are used for every sorting
  558.         * pass...this lessens the possibility of timing changes due to
  559.         * order dependency of the routine.
  560.         */
  561.  
  562.        for(i=0; i < 30000; i++) sarray[i] = (i % 2) ? (WORD)30000-i : (WORD)i;
  563.  
  564.        gap = 30000 / 2;
  565.        do {
  566.          do {
  567.             nex = FALSE;
  568.             for(i=0; i < 30000-gap; i++)
  569.             {
  570.                if(sarray[i] > sarray[i+gap])
  571.                {
  572.                   temp = sarray[i];
  573.                   sarray[i] = sarray[i+gap];
  574.                   sarray[i+gap] = temp;
  575.                   nex = TRUE;
  576.                }
  577.             }
  578.          } while(nex);
  579.          gap /= 2;
  580.        } while(gap);
  581.     }
  582.  
  583.     STOP_TEST_TIMER;
  584.  
  585.     /* Clean up code and result calculation should follow at this point. */
  586.  
  587.     ...................................................................
  588. }
  589.  
  590. ==============================================================================
  591.  
  592.                                    TGTest
  593.  
  594.     Text and Graphics Test.  This is a test of the text throughput on the
  595. system in question.  Since OS calls are used again, this will have an advantage
  596. on systems with the OS kernel in a fast memory medium, and will also have
  597. advantage on those systems with more efficiency CHIP RAM access.  There are
  598. also some position variables which are calculated during the test, so this
  599. does not simply show the speed of the various text routines used, but also
  600. the overall efficiency of system when executing the routine's entire job.
  601. A decision step is also involved in drawing mode selection, thus contributing
  602. to the overall view of the text output and calculation efficiency of the
  603. system.  This test also tends to reflect the efficiency of the system
  604. whe utilizing various windowing routines.
  605.  
  606. void TGTest()
  607. {
  608.     struct Screen *TTScrn;
  609.     struct Window *TTWin;
  610.     struct RastPort *TTRp;
  611.     UWORD opens;
  612.     UWORD xpos;
  613.     UWORD ypos = 29;
  614.     UWORD scrolls = 0;
  615.     UWORD color = 0;
  616.     UWORD drmd = JAM1;
  617.  
  618.     if(!(TTScrn = OpenScreen(&TTNewScrn))) return(FALSE);
  619.     LoadRGB4(&(TTScrn->ViewPort),TGTstCols,16);
  620.     ScreenToFront(TTScrn);
  621.     TTNewWin.Screen = TTScrn;
  622.  
  623.     START_TEST_TIMER;
  624.  
  625.     for(opens = 0; opens < 7; opens++)
  626.     {
  627.         TTNewWin.Width -= (opens * 20);
  628.         TTNewWin.Height -= (opens * 10);
  629.         TTNewWin.LeftEdge = (opens * 20);
  630.         TTNewWin.TopEdge = (opens * 10);
  631.         if(!(TTWin = OpenWindow(&TTNewWin)))
  632.         {
  633.            STOP_TEST_TIMER;
  634.            CloseScreen(TTScrn);
  635.            return(FALSE);
  636.         }
  637.  
  638.         TTRp = TTWin->RPort;
  639.         SetDrMd(TTRp,drmd);
  640.         SetAPen(TTRp,color);
  641.  
  642.         while(scrolls < 30)
  643.         {
  644.            xpos = 20;
  645.            while(xpos < (TTWin->Width -  (TextLength(TTRp,TestStr,strlen(TestStr)) + 9)))
  646.            {
  647.               switch(drmd)
  648.               {
  649.                  case JAM1 :
  650.                       drmd = JAM2;
  651.                       break;
  652.                  case JAM2 :
  653.                       drmd = COMPLEMENT;
  654.                       break;
  655.                  case COMPLEMENT :
  656.                       drmd = INVERSVID;
  657.                       break;
  658.                  case INVERSVID :
  659.                       drmd = JAM1;
  660.                       break;
  661.               }
  662.               SetDrMd(TTRp,drmd);
  663.               color = (color == 15) ? 0 : color + 1;
  664.               SetAPen(TTRp,(color = (color == 15) ? 0 : color + 1));
  665.               if(drmd != JAM1) SetBPen(TTRp,(color > 1) ? color-2 : color + 1);
  666.  
  667.                Move(TTRp,xpos,ypos);
  668.                Text(TTRp,TestStr,strlen(TestStr));
  669.  
  670.                xpos += TextLength(TTRp,TestStr,strlen(TestStr));
  671.            }
  672.            ypos += 9;
  673.            if(ypos > (TTWin->Height - 20))
  674.            {
  675.               ypos = (TTWin->Height - 20);
  676.               ScrollRaster(TTRp,0,9,15,22,(TTWin->Width - 12),(TTWin->Height - 18));
  677.               scrolls++;
  678.            }
  679.         }
  680.         CloseWindow(TTWin);
  681.         SetRast(&(TTScrn->RastPort),0);
  682.         ypos = 29; scrolls = 0; color = 0;
  683.     }
  684.  
  685.     STOP_TEST_TIMER;
  686.  
  687.     /* Clean up routines should follow at this point */
  688.  
  689.     ..................................................................
  690. }
  691.  
  692. ==============================================================================
  693.  
  694.                                    FMath
  695.  
  696.     The FMath test is very similar to the IMath test with the exception that
  697. floating point math is the primary interest as opposed to integer operations.
  698. Single-precision operations are utilized for this test.  The rough code
  699. outline is given below:
  700.  
  701.  
  702. void FMath()
  703. {
  704.     float a;
  705.     float b;
  706.     float c;
  707.     UWORD i;
  708.  
  709.     a = 45.43;
  710.     b = 2.22;
  711.     c = 2.0;
  712.  
  713.     START_TEST_TIMER;
  714.  
  715.     for(i=0; i < 20000 ; i++)
  716.     {
  717.        a = (a * b) + (float)i;
  718.        c += ((a * b) / (float)i) + 1.0;
  719.        c -= (c / a) - (float)i;
  720.        c += ((c / a) * (float)i) + 1.0;
  721.        a = (a * b) + (float)i;
  722.        c -= (c / a) - (float)i;
  723.        c += ((a * b) / (float)i) + 1.0;
  724.        c -= ((c / a) * (float)i) + 1.0;
  725.        a = (a * b) + (float)i;
  726.        c += (c / a) - (float)i;
  727.        c -= ((a * b) / (float)i) + 1.0;
  728.        c += ((c / a) * (float)i) + 1.0;
  729.        a = (a * b) + (float)i;
  730.        c -= (c / a) - (float)i;
  731.     }
  732.  
  733.     STOP_TEST_TIMER;
  734.  
  735.     /*
  736.      *  Again, at this point a global 'dummy' variable is used to assure that
  737.      *  code above is not optimized out.  This makes a global optimizer
  738.      *  believe the above results are needed in order to assign the
  739.      *  dummy variable a value
  740.      */
  741.  
  742.     TestFltDummy = a+b+c;
  743.  
  744.     ....................................................................
  745. }
  746.  
  747. ==============================================================================
  748.  
  749.                                   FMatrix
  750.  
  751.     The FMatrix test is almost completely identical to the standard integer
  752. matrix test, with the exception that the data being manipulated is double
  753. precision floating point numbers.  The code outline is given below:
  754.  
  755.  
  756. void FMatrix()
  757. {
  758.     double *MatrixA;
  759.     double *MatrixB;
  760.     double *MatrixC;
  761.     UWORD i;
  762.     UWORD j;
  763.     UWORD k;
  764.  
  765.     /*
  766.      * Not shown: The 3 matrices must be allocated ( 12800 bytes each )
  767.      * for the following test.  Next, shown below, matrices A and B are
  768.      * initialized with data.
  769.      */
  770.  
  771.     for(i=0; i < 40; i++)
  772.     {
  773.       for(j=0; j < 40; j++)
  774.       {
  775.           MatrixA[40*i+j] = (double)(i+j);
  776.           MatrixB[40*i+j] = (double)(i+j) * (double)(j-i);
  777.       }
  778.     }
  779.  
  780.     /*
  781.      * The actual test code begins below.
  782.      */
  783.  
  784.     START_TEST_TIMER;
  785.  
  786.     for(k=0; k < 50; k++)
  787.     {
  788.        fmatrix_mult(MatrixA,MatrixB,MatrixC,40,40);
  789.        for(i=0; i < 40; i++)
  790.        {
  791.           fmatrix_row_swap(MatrixC,i,39-i,40);
  792.           fmatrix_col_swap(MatrixC,39-i,i,40);
  793.        }
  794.        fmatrix_add(MatrixC,MatrixA,MatrixB,40,40);
  795.        fmatrix_sub(MatrixB,MatrixA,MatrixC,40,40);
  796.        fmatrix_transpose(MatrixC,MatrixA,40,40);
  797.     }
  798.  
  799.     STOP_TEST_TIMER;
  800.  
  801.     /*
  802.      * Again, clean-up and memory deallocation is performed here, though
  803.      * not shown.
  804.      */
  805.  
  806.      ..................................................................
  807. }
  808.  
  809. /*
  810.  * This function swaps rows in a double FP matrix.
  811.  */
  812.  
  813. void fmatrix_row_swap(double *mat, UWORD ra, UWORD rb, UWORD ncols)
  814. {
  815.     UWORD c;
  816.     double t;
  817.  
  818.     for(c=0; c < ncols; c++)
  819.     {
  820.        t = mat[ra*ncols+c];
  821.        mat[ra*ncols+c] = mat[rb*ncols+c];
  822.        mat[rb*ncols+c] = t;
  823.     }
  824. }
  825.  
  826. void fmatrix_col_swap(double *mat, UWORD ca, UWORD cb, UWORD nrows)
  827. {
  828.     UWORD r;
  829.     double t;
  830.  
  831.     for(r=0; r < nrows; r++)
  832.     {
  833.        t = mat[r*nrows+ca];
  834.        mat[r*nrows+ca] = mat[r*nrows+cb];
  835.        mat[r*nrows+cb] = t;
  836.     }
  837. }
  838.  
  839. /*
  840.  * Add the contents of two FP matrices, and store the result in a third.
  841.  * Equivalent to [C] = [A] + [B]
  842.  */
  843.  
  844. void fmatrix_add(double *matA, double *matB, double *matC, UWORD rows, UWORD cols)
  845. {
  846.      UWORD r;
  847.      UWORD c;
  848.  
  849.     for(r=0; r < rows; r++)
  850.     {
  851.        for(c=0; c < cols; c++)
  852.        {
  853.           matC[r*cols+c] = matA[r*cols+c] + matB[r*cols+c];
  854.        }
  855.     }
  856. }
  857.  
  858. /*
  859.  * Subtract the contents of two FP matrices, and store the result in a third.
  860.  * Equivalent to [C] = [A] - [B].
  861.  */
  862.  
  863. void fmatrix_sub(double *matA, double *matB, double *matC, UWORD rows, UWORD cols)
  864. {
  865.     UWORD r;
  866.     UWORD c;
  867.  
  868.     for(r=0; r < rows; r++)
  869.     {
  870.        for(c=0; c < cols; c++)
  871.        {
  872.           matC[r*cols+c] = matA[r*cols+c] - matB[r*cols+c];
  873.        }
  874.     }
  875. }
  876.  
  877. /*
  878.  * Subtract the contents of two FP matrices, and store the result in a third.
  879.  * Equivalent to [C] = [A] * [B].
  880.  */
  881.  
  882. void fmatrix_mult(double *matA, double *matB, double *matC, UWORD rows, UWORD cols)
  883. {
  884.     UWORD r;
  885.     UWORD c;
  886.  
  887.     for(r=0; r < rows; r++)
  888.     {
  889.        for(c=0; c < cols; c++)
  890.        {
  891.           matC[r*cols+c] = matA[r*cols+c] * matB[r*cols+c];
  892.        }
  893.     }
  894. }
  895.  
  896. /*
  897.  * Transpose the contents of FP matrix [B] to FP matrix [A]
  898.  */
  899.  
  900. void fmatrix_transpose(double *matA, double *matB, UWORD rows, UWORD cols)
  901. {
  902.     UWORD r;
  903.     UWORD c;
  904.     double t;
  905.  
  906.     for(r=0; r < rows; r++)
  907.     {
  908.        for(c=0; c < cols; c++)
  909.        {
  910.           t = matA[r*cols+c];
  911.           matA[r*cols+c] = matB[r*cols+c];
  912.           matB[r*cols+c] = t;
  913.        }
  914.     }
  915. }
  916.  
  917.  
  918. ==============================================================================
  919.  
  920.                                   Savage
  921.  
  922.     The Savage benchmark is a test almost exclusively consisting of floating-
  923. point transcendental functions.  It is a fairly well known test, used a fair
  924. amount for basic trancendental function evaluation.  It is very simple in
  925. nature, as can be seen below:
  926.  
  927. void Savage()
  928. {
  929.     UWORD i;
  930.     double a = 1.0L;
  931.  
  932.     START_TEST_TIMER;
  933.  
  934.     for(i=0; i < 40000; i++)
  935.     {
  936.         a = tan(atan(exp(log(sqrt(a*a))))) + 1.0L;
  937.     }
  938.  
  939.     STOP_TEST_TIMER;
  940.  
  941.     /*
  942.      * And that's the basic essence to the test...
  943.      */
  944.  
  945.      ...........................................................
  946. }
  947.  
  948. ===========================================================================
  949.                                Whetstone
  950.  
  951.     The Whetstone test is a fairly popular, albeit older, test of system
  952. performance.  Because it deals with floating point as well as other
  953. areas, it is placed in the floating point test category.  The test has
  954. been slightly modified in that the accuracy tests it does (checks) have
  955. been replaced...a function call is still used to maintain the integrity of
  956. the test, but accuracy is not a testing concern in this setup.
  957.  
  958. void Whetstone_Test()
  959. {
  960.     BOOL tempbool;
  961.  
  962.     START_TEST_TIMER;
  963.  
  964.     n1_O  = 2L * wt_O;
  965.     n2_O  = 10L * wt_O;
  966.     n3_O  = 14L * wt_O;
  967.     n4_O  = 345L * wt_O;
  968.     n5_O  = 0L;
  969.     n6_O  = 95L * wt_O;
  970.     n7_O  = 32L * wt_O;
  971.     n8_O  = 800L * wt_O;
  972.     n9_O  = 616L * wt_O;
  973.     n10_O = 0L;
  974.     n11_O = 93L * wt_O;
  975.  
  976.     /***********************************/
  977.     /*  MODULE  1: Simple Identifiers  */
  978.     /***********************************/
  979.  
  980.     xx_O_d.one   =  1.0;
  981.     xx_O_d.two   = -1.0;
  982.     xx_O_d.three = -1.0;
  983.     xx_O_d.four  = -1.0;
  984.  
  985.     for(i_O = 0L; i_O < n1_O; i_O++)
  986.     {
  987.        xx_O_d.one   = ( xx_O_d.one + xx_O_d.two + xx_O_d.three - xx_O_d.four ) * T;
  988.        xx_O_d.two   = ( xx_O_d.one + xx_O_d.two - xx_O_d.three + xx_O_d.four ) * T;
  989.        xx_O_d.three = ( xx_O_d.one - xx_O_d.two + xx_O_d.three + xx_O_d.four ) * T;
  990.        xx_O_d.four  = (-xx_O_d.one + xx_O_d.two + xx_O_d.three + xx_O_d.four ) * T;
  991.     }
  992.  
  993.     norm_O_d = sqrt(sqr(xx_O_d.one)+sqr(xx_O_d.two)+sqr(xx_O_d.three)+sqr(xx_O_d.four));
  994.     tempbool = ((fabs(norm_O_d - exp(0.35735-n1_O*6.1e-5))/norm_O_d) <= 0.1);
  995.     Check(1,tempbool);
  996.  
  997.    /*******************************/
  998.    /*  MODULE  2: Array Elements  */
  999.    /*******************************/
  1000.  
  1001.     e1_O_d[0] =  1.0;
  1002.     e1_O_d[1] = -1.0;
  1003.     e1_O_d[2] = -1.0;
  1004.     e1_O_d[3] = -1.0;
  1005.  
  1006.     for(i_O=0L; i_O < n2_O; i_O++)
  1007.     {
  1008.        e1_O_d[0] = ( e1_O_d[0] + e1_O_d[1] + e1_O_d[2] - e1_O_d[3] ) * T;
  1009.        e1_O_d[1] = ( e1_O_d[0] + e1_O_d[1] - e1_O_d[2] + e1_O_d[3] ) * T;
  1010.        e1_O_d[2] = ( e1_O_d[0] - e1_O_d[1] + e1_O_d[2] + e1_O_d[3] ) * T;
  1011.        e1_O_d[3] = (-e1_O_d[0] + e1_O_d[1] + e1_O_d[2] + e1_O_d[3] ) * T;
  1012.     }
  1013.  
  1014.     norm_O_d = sqrt(sqr(e1_O_d[0])+sqr(e1_O_d[1])+sqr(e1_O_d[2])+sqr(e1_O_d[3]));
  1015.     tempbool = ((fabs(norm_O_d - exp(0.35735-n2_O*6.1e-5))/norm_O_d) <= 0.1);
  1016.     Check(2,tempbool);
  1017.  
  1018.     /*************************************/
  1019.     /*  MODULE  3: Array as a Parameter  */
  1020.     /*************************************/
  1021.  
  1022.     t3_O_d = 1.0 / T;
  1023.  
  1024.     for(i_O = 0; i_O < n3_O; i_O++) pa(e1_O_d);
  1025.  
  1026.     norm_O_d = sqrt(sqr(e1_O_d[0])+sqr(e1_O_d[1])+sqr(e1_O_d[2])+sqr(e1_O_d[3]));
  1027.     tempbool = ((fabs(norm_O_d - exp(0.35735-(n3_O*6+n2_O)*6.1e-5))/norm_O_d) <= 0.1);
  1028.     Check(3,tempbool);
  1029.  
  1030.     /**********************************/
  1031.     /*  MODULE  4: Conditional Jumps  */
  1032.     /**********************************/
  1033.  
  1034.     jj_O = 1L;
  1035.  
  1036.     for(i_O = 0; i_O < n4_O; i_O++)
  1037.     {
  1038.        if(jj_O == 1L)
  1039.           jj_O = 2L;
  1040.        else
  1041.           jj_O = 3L;
  1042.        if(jj_O > 2L)
  1043.           jj_O = 0L;
  1044.        else
  1045.           jj_O = 1L;
  1046.        if(jj_O < 1L)
  1047.           jj_O = 1L;
  1048.        else
  1049.          jj_O = 0L;
  1050.     }
  1051.     tempbool = (jj_O == (!(wt_O & 1L)));
  1052.     Check(4,tempbool);
  1053.  
  1054.     /***********************************/
  1055.     /*  MODULE  6: Integer Arithmetic  */
  1056.     /***********************************/
  1057.  
  1058.     ij_O = 1;
  1059.     ik_O = 2;
  1060.     il_O = 3;
  1061.  
  1062.     for(i_O=0 ; i_O < n6_O; i_O++)
  1063.     {
  1064.        ij_O =  ij_O * (ik_O - ij_O) * (il_O - ik_O);
  1065.        ik_O =  il_O * ik_O - (il_O - ij_O) * ik_O;
  1066.        il_O = (il_O - ik_O) * (ik_O + ij_O);
  1067.  
  1068.        e1_O_d[il_O-2] = ij_O + ik_O + il_O;
  1069.        e1_O_d[ik_O-2] = ij_O * ik_O * il_O;
  1070.     }
  1071.  
  1072.     tempbool = ((ij_O==1L) && (ik_O==2L) && (il_O==3L));
  1073.     Check(6,tempbool);
  1074.  
  1075.     /****************************************/
  1076.     /*  MODULE  7: Trigonometric Functions  */
  1077.     /****************************************/
  1078.  
  1079.     x_O_d = 0.5;
  1080.     y_O_d = 0.5;
  1081.  
  1082.     for(i_O=0L; i_O < n7_O; i_O++)
  1083.     {
  1084.        x_O_d = T * atan(T2 * sin(x_O_d) * cos(x_O_d) / (cos(x_O_d+y_O_d) + cos(x_O_d-y_O_d) - 1.0));
  1085.        y_O_d = T * atan(T2 * sin(y_O_d) * cos(y_O_d) / (cos(x_O_d+y_O_d) + cos(x_O_d-y_O_d) - 1.0));
  1086.     }
  1087.  
  1088.     tempbool = (((T - wt_O * 0.0015) <= x_O_d) && (x_O_d <= (T - wt_O * 0.0004)) &&
  1089.                 ((T - wt_O * 0.0015) <= y_O_d) && (y_O_d <= (T - wt_O * 0.0004)));
  1090.     Check(7,tempbool);
  1091.  
  1092.    /********************************/
  1093.    /*  MODULE  8: Procedure Calls  */
  1094.    /********************************/
  1095.  
  1096.     x_O_d = 1.0;
  1097.     y_O_d = 1.0;
  1098.     z_O_d = 1.0;
  1099.  
  1100.     for(i_O = 1L; i_O <= n8_O; i_O++) p3((double)(y_O_d*(double)i_O),(double)(y_O_d+z_O_d),&z_O_d);
  1101.     tempbool = ((fabs(z_O_d - (0.99983352*n8_O - 0.999555651))) <= (n8_O*1.0e-6));
  1102.     Check(8,tempbool);
  1103.  
  1104.     /*********************************/
  1105.     /*  MODULE  9: Array References  */
  1106.     /*********************************/
  1107.  
  1108.     ij_O = 0;
  1109.     ik_O = 1;
  1110.     il_O = 2;
  1111.  
  1112.     e1_O_d[0] = 1.0;
  1113.     e1_O_d[1] = 2.0;
  1114.     e1_O_d[2] = 3.0;
  1115.  
  1116.     for(i_O=0L; i_O < n9_O; i_O++) p0();
  1117.  
  1118.     tempbool = ((e1_O_d[0] == 3.0) && (e1_O_d[1] == 2.0) && (e1_O_d[2] == 3.0));
  1119.     Check(9,tempbool);
  1120.  
  1121.     /***********************************/
  1122.     /*  MODULE 10: Integer Arithmetic  */
  1123.     /***********************************/
  1124.  
  1125.     jj_O = 2L;
  1126.     kk_O = 3L;
  1127.  
  1128.     for(i_O=0;i_O<n10_O;i_O++)
  1129.     {
  1130.        jj_O = jj_O + kk_O;
  1131.        kk_O = jj_O + kk_O;
  1132.        jj_O = kk_O - jj_O;
  1133.        kk_O = kk_O - jj_O - jj_O;
  1134.     }
  1135.     tempbool = ((jj_O==2) && (kk_O==3));
  1136.     Check(10,tempbool);
  1137.  
  1138.     /***********************************/
  1139.     /*  MODULE 11: Standard Functions  */
  1140.     /***********************************/
  1141.  
  1142.     x_O_d = 0.75;
  1143.  
  1144.     for(i_O = 0L; i_O < n11_O; i_O++) x_O_d = sqrt(exp(log(x_O_d) / T1));
  1145.  
  1146.     estimate_O_d = 1.0L - exp(-0.0447L*wt_O + log(0.26L));
  1147.     tempbool = ((fabs(estimate_O_d-x_O_d)/estimate_O_d <= (0.0006 + 0.065/(5.0+(double)wt_O))));
  1148.     Check(11,tempbool);
  1149.  
  1150.    /**************************************/
  1151.  
  1152.     STOP_TEST_TIMER;
  1153.  
  1154.     /*
  1155.      * Cleanup and result calculations are omitted here, as the main
  1156.      * portion of the actual test is the concern.
  1157.      */
  1158.  
  1159. }
  1160.  
  1161. static double sqr(register double x)
  1162. {
  1163.     x *= x;
  1164.     return(x);
  1165. }
  1166.  
  1167. static void pa(register double *e)
  1168. {
  1169.     register WORD j = 0;
  1170.  
  1171.     do {
  1172.          e[0] = ( e[0] + e[1] + e[2] - e[3] ) * T;
  1173.          e[1] = ( e[0] + e[1] - e[2] + e[3] ) * T;
  1174.          e[2] = ( e[0] - e[1] + e[2] + e[3] ) * T;
  1175.          e[3] = (-e[0] + e[1] + e[2] + e[3] ) / t3_O_d;
  1176.          j++;
  1177.     } while(j < 6);
  1178. }
  1179.  
  1180.  
  1181. static void p0()
  1182. {
  1183.     e1_O_d[ij_O] = e1_O_d[ik_O];
  1184.     e1_O_d[ik_O] = e1_O_d[il_O];
  1185.     e1_O_d[il_O] = e1_O_d[ij_O];
  1186. }
  1187.  
  1188. static void p3(register double x, register double y, register double *z)
  1189. {
  1190.     x = T * (*z + x);
  1191.     y = T * (x + y);
  1192.     *z = (x + y) / T2;
  1193. }
  1194.  
  1195. static BOOL Check(register UWORD ModuleNo, register BOOL Condition)
  1196. {
  1197.    return((Condition) ? TRUE : FALSE);
  1198. }
  1199.  
  1200. ===========================================================================
  1201.                                  FTrace
  1202.  
  1203.     The FTrace test is in actuality a portion of a ray-tracing algorithm
  1204. set in use as a benchmark.  Its construction is fairly simple, and the
  1205. main outline is given below:
  1206.  
  1207. BOOL FTrace_CP_N()
  1208. {
  1209.     WORD iter;
  1210.     double od_fline;
  1211.     double od_cline;
  1212.     ULONG nulltime;
  1213.  
  1214.     /*
  1215.      * Initialization not shown to focus on the main test itself
  1216.      */
  1217.  
  1218.     START_TEST_TIMER;
  1219.  
  1220.     for(iter=0; iter < LOOPCOUNT; iter++)
  1221.     {
  1222.        for(paraxial=0; paraxial <= 1; paraxial++)
  1223.        {
  1224.           trace_line(4,clear_aperture / 2.0L);
  1225.           od_sa[paraxial][0] = object_distance;
  1226.           od_sa[paraxial][1] = axis_slope_angle;
  1227.        }
  1228.        paraxial = 0;
  1229.        trace_line(3,clear_aperture / 2.0L);
  1230.        od_cline = object_distance;
  1231.        trace_line(6,clear_aperture / 2.0L);
  1232.        od_fline = object_distance;
  1233.        aberr_lspher = od_sa[1][0] - od_sa[0][0];
  1234.        aberr_osc = 1.0L - (od_sa[1][0] * od_sa[1][1]) /
  1235.                           (sin(od_sa[0][1]) * od_sa[0][0]);
  1236.        aberr_lchrom = od_fline - od_cline;
  1237.        max_lspher = sin(od_sa[0][1]);
  1238.        max_lspher = 0.0000926L / (max_lspher * max_lspher);
  1239.        max_osc = 0.0025L;
  1240.        max_lchrom = max_lspher;
  1241.     }
  1242.  
  1243.     STOP_TEST_TIMER;
  1244.  
  1245.     ..............................................................
  1246. }
  1247.  
  1248. /*-----------------------------------------------------------------------------*/
  1249.  
  1250. void trace_line(register WORD line, register double ray_h)
  1251. {
  1252.     register WORD i;
  1253.  
  1254.     object_distance = 0.0L;
  1255.     ray_height = ray_h;
  1256.     from_index = 1.0L;
  1257.  
  1258.     for(i = 1; i <= current_surfaces; i++)
  1259.     {
  1260.        radius_of_curvature = s[i][1];
  1261.        to_index = s[i][2];
  1262.        if(to_index > 1.0L)
  1263.           to_index = to_index + ((spectral_line[4] - spectral_line[line]) /
  1264.                      (spectral_line[3] - spectral_line[6])) *
  1265.                      ((s[i][2] - 1.0L) / s[i][3]);
  1266.        transit_surface();
  1267.        from_index = to_index;
  1268.        if(i < current_surfaces) object_distance = object_distance - s[i][4];
  1269.     }
  1270. }
  1271.  
  1272. /*----------------------------------------------------------------------------*/
  1273.  
  1274. void transit_surface()
  1275. {
  1276.     register double iang;               /* Incidence angle */
  1277.     register double rang;
  1278.     register double iang_sin;
  1279.     register double rang_sin;
  1280.     double old_axis_slope_angle;
  1281.     double sagitta;
  1282.  
  1283.     if(paraxial)
  1284.     {
  1285.        if(radius_of_curvature != 0.0L)
  1286.        {
  1287.           if(object_distance == 0.0L)
  1288.           {
  1289.              axis_slope_angle = 0.0L;
  1290.              iang_sin = ray_height / radius_of_curvature;
  1291.           }
  1292.           else
  1293.              iang_sin = ((object_distance - radius_of_curvature) /
  1294.                           radius_of_curvature) * axis_slope_angle;
  1295.  
  1296.           rang_sin = (from_index / to_index) * iang_sin;
  1297.           old_axis_slope_angle = axis_slope_angle;
  1298.           axis_slope_angle = axis_slope_angle + iang_sin - rang_sin;
  1299.           if(object_distance != 0.0L)
  1300.              ray_height = object_distance * old_axis_slope_angle;
  1301.           object_distance = ray_height / axis_slope_angle;
  1302.           return;
  1303.        }
  1304.        object_distance = object_distance * (to_index / from_index);
  1305.        axis_slope_angle = axis_slope_angle * (from_index / to_index);
  1306.        return;
  1307.     }
  1308.  
  1309.     if(radius_of_curvature != 0.0L)
  1310.     {
  1311.        if(object_distance == 0.0L)
  1312.        {
  1313.           axis_slope_angle = 0.0L;
  1314.           iang_sin = ray_height / radius_of_curvature;
  1315.        }
  1316.        else
  1317.        {
  1318.           iang_sin = ((object_distance - radius_of_curvature) /
  1319.                        radius_of_curvature) * sin(axis_slope_angle);
  1320.        }
  1321.        iang = asin(iang_sin);
  1322.        rang_sin = (from_index / to_index) * iang_sin;
  1323.        old_axis_slope_angle = axis_slope_angle;
  1324.        axis_slope_angle = axis_slope_angle + iang - asin(rang_sin);
  1325.        sagitta = sin((old_axis_slope_angle + iang) / 2.0L);
  1326.        sagitta = 2.0L * radius_of_curvature*sagitta*sagitta;
  1327.        object_distance = ((radius_of_curvature *
  1328.                            sin(old_axis_slope_angle + iang)) *
  1329.                            cot(axis_slope_angle)) + sagitta;
  1330.        return;
  1331.     }
  1332.  
  1333.     rang = -asin((from_index / to_index) * sin(axis_slope_angle));
  1334.     object_distance = object_distance * ((to_index * cos(-rang)) /
  1335.                       (from_index * cos(axis_slope_angle)));
  1336.     axis_slope_angle = -rang;
  1337. }
  1338.  
  1339. ===========================================================================
  1340.                               CplxTest
  1341.  
  1342.     The CplxTest is a simple test of complex arithmetic methods.  Complex
  1343. arithmetic finds its use in many scientific and engineering fields and
  1344. some basic arithmetic using this number form is applied for this test.
  1345.  
  1346.  
  1347. typedef struct cplx {
  1348.                       double  r;
  1349.                       double  i;
  1350.                     } complex;
  1351.  
  1352. void CplxTest()
  1353. {
  1354.     UWORD i;
  1355.     complex c1 = { 0.243223L,1.23412L };
  1356.     complex c2 = { -0.243222L,-1.23412L };
  1357.  
  1358.     START_TEST_TIMER;
  1359.  
  1360.     for(i=0; i < 3000; i++)
  1361.     {
  1362.        c1.r = creal(c1);
  1363.        c1.i = cimg(c1);
  1364.        c2.r = -(creal(c2));
  1365.        c2.i = -(cimg(c2));
  1366.  
  1367.        c1 = cadd(c1,c2);
  1368.        c2 = csub(c2,c1);
  1369.        c2 = cdiv(cmul(cinv(c1),cneg(c2)) ,c1);
  1370.        c1 = cexp(conj(c2));
  1371.        c1 = ccosh(csub(c1,c2));
  1372.        c2 = cmul(cdiv(c1,c2),cdiv(c2,c1));
  1373.        c2 = cexp(cadd(conj(c2),conj(c1)));
  1374.     }
  1375.  
  1376.     STOP_TEST_TIMER;
  1377.  
  1378.     .............................................................
  1379.  
  1380. }
  1381.  
  1382. complex cadd(complex o1, complex o2)
  1383. {
  1384.    complex __aligned a1;
  1385.  
  1386.    a1.r = o1.r + o2.r;
  1387.    a1.i = o1.i + o2.i;
  1388.    return(a1);
  1389. }
  1390.  
  1391. complex csub(complex o1, complex o2)
  1392. {
  1393.    complex __aligned a1;
  1394.  
  1395.    a1.r = o1.r - o2.r;
  1396.    a1.i = o1.i - o2.i;
  1397.    return(a1);
  1398. }
  1399.  
  1400. complex cmul(complex o1, complex o2)
  1401. {
  1402.    complex __aligned a1;
  1403.  
  1404.    a1.r = (o1.r * o2.r) - (o1.i * o2.i);
  1405.    a1.i = (o1.r * o2.i) + (o1.i * o2.r);
  1406.    return(a1);
  1407. }
  1408.  
  1409. complex cinv(complex o1)
  1410. {
  1411.    double __aligned mag;
  1412.    complex __aligned a1;
  1413.  
  1414.    mag = (o1.r * o1.r) + (o1.i * o1.i);
  1415.    a1.r = o1.r / mag;
  1416.    a1.i = o1.i / mag;
  1417.    return(a1);
  1418. }
  1419.  
  1420. complex cneg(complex o1)
  1421. {
  1422.    complex __aligned a1;
  1423.  
  1424.    a1.r = -o1.r;
  1425.    a1.i = -o1.i;
  1426.    return(a1);
  1427. }
  1428.  
  1429. complex cdiv(complex o1, complex o2)
  1430. {
  1431.    return(cmul(o1,cinv(o2)));
  1432. }
  1433.  
  1434. complex conj(complex o1)
  1435. {
  1436.    complex __aligned a1;
  1437.  
  1438.    a1.r = o1.r;
  1439.    a1.i = -o1.i;
  1440.    return(a1);
  1441. }
  1442.  
  1443. complex cexp(complex o1)
  1444. {
  1445.    double __aligned mag;
  1446.    complex __aligned a1;
  1447.  
  1448.    mag = exp(o1.r);
  1449.    a1.r = mag * cos(o1.i);
  1450.    a1.i = mag * sin(o1.i);
  1451.    return(a1);
  1452. }
  1453.  
  1454. complex ccosh(complex o1)
  1455. {
  1456.    complex __aligned a1;
  1457.  
  1458.    a1 = cadd(cexp(o1),cexp(cneg(o1)));
  1459.    a1.r = 0.5 * a1.r;
  1460.    a1.i = 0.5 * a1.i;
  1461.    return(a1);
  1462. }
  1463.  
  1464. double creal(complex o1)
  1465. {
  1466.    return(o1.r);
  1467. }
  1468.  
  1469. double cimg(complex o1)
  1470. {
  1471.    return(o1.i);
  1472. }
  1473.